
#include "spi_v1.hpp"

#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdexcept>
#include <cstring>   // for memset
#include <vector>    // for temporary buffers
#include <algorithm> // for std::max, std::copy
#include <iomanip>
#include <glog/logging.h>

spi_v1::spi_v1(std::string device_path,
               uint32_t speed_hz,
               spi_mode_en mode,
               uint8_t bits_per_word)
    : _device_path(device_path),
      _speed_hz(speed_hz),
      _mode(mode),
      _bits_per_word(bits_per_word)
{
    _fd = open(device_path.c_str(), O_RDWR);
    if (_fd < 0)
    {
        LOG(ERROR) << "Failed to open SPI device: " << device_path;
        _is_open_flag = YJ_ERROR;
        return;
    }


    _configure();
    _is_open_flag = YJ_OK;
}

spi_v1::~spi_v1()
{
    if (_fd >= 0)
    {
        close(_fd);
    }
}

yj_return spi_v1::_configure()
{
    if (ioctl(_fd, SPI_IOC_WR_MODE, &_mode) < 0 ||
        ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &_bits_per_word) < 0 ||
        ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_speed_hz) < 0)
    {
        LOG(ERROR) << "Failed to configure SPI";
        return YJ_ERROR;
    }
    return YJ_OK;
}

yj_return spi_v1::transfer_and_recv(const uint8_t *tx_buffer,
                                   size_t tx_length,
                                   uint8_t *rx_buffer,
                                   size_t rx_length,
                                   uint16_t delay_after_send_us)
{
    if(_is_open_flag != YJ_OK)
    {
        LOG(ERROR) << "SPI is not open correctly";
        return YJ_ERROR;
    }

    if (tx_length == 0 && rx_length == 0)
    {
        return YJ_OK;
    }

    // 创建一个足够大的缓冲区，包含发送数据和接收数据阶段
    size_t total_length = tx_length + rx_length;
    std::vector<uint8_t> tx_temp(total_length, 0);  // 发送缓冲区，接收数据阶段填充0
    std::vector<uint8_t> rx_temp(total_length, 0);  // 接收缓冲区
    
    // 复制发送数据到缓冲区开头
    if (tx_length > 0 && tx_buffer != nullptr)
    {
        std::copy(tx_buffer, tx_buffer + tx_length, tx_temp.begin());
    }
    
    // 设置单个传输
    struct spi_ioc_transfer tr;
    std::memset(&tr, 0, sizeof(tr));
    
    tr.tx_buf = reinterpret_cast<unsigned long>(tx_temp.data());
    tr.rx_buf = reinterpret_cast<unsigned long>(rx_temp.data());
    tr.len = total_length;
    tr.speed_hz = _speed_hz;
    tr.bits_per_word = _bits_per_word;
    tr.delay_usecs = 0; // 不需要额外延迟
    tr.cs_change = 0;
    
    // 执行传输
    if (ioctl(_fd, SPI_IOC_MESSAGE(1), &tr) < 0)
    {
        LOG(ERROR) << "SPI transfer failed";
        return YJ_ERROR;
    }
    
    // 复制接收到的数据（跳过发送阶段的数据）
    if (rx_length > 0 && rx_buffer != nullptr)
    {
        std::copy(rx_temp.begin() + tx_length, rx_temp.begin() + total_length, rx_buffer);
    }
    
    return YJ_OK;
}


yj_return spi_v1::set_speed(uint32_t speed_hz)
{
    uint32_t temp_speed = _speed_hz;
    _speed_hz = speed_hz;
    if (_configure() != YJ_OK)
    {
        LOG(ERROR) << "Failed to configure SPI speed";
        _speed_hz = temp_speed;
        return YJ_ERROR;
    }
    return YJ_OK;
}

yj_return spi_v1::set_mode(spi_mode_en mode)
{
    uint8_t temp_mode = _mode;
    _mode = mode;
    if (_configure() != YJ_OK)
    {
        LOG(ERROR) << "Failed to configure SPI mode";
        _mode = temp_mode;
        return YJ_ERROR;
    }
    return YJ_OK;
}

yj_return spi_v1::set_bits_per_word(uint8_t bits)
{
    uint8_t temp_bits = _bits_per_word;
    _bits_per_word = bits;
    if (_configure() != YJ_OK)
    {
        LOG(ERROR) << "Failed to configure SPI bits per word";
        _bits_per_word = temp_bits;
        return YJ_ERROR;
    }
    return YJ_OK;
}